Skip to content

Conversation

@schplitt
Copy link

🔗 Linked issue

resolves #7

📚 Description

This PR adds support for early nitro v3 alpha versions under the evlog/nitrov3 scope.
Hope that is alright.

I move shared nitro utilities to a seperate file.
I have adjusted the docs aswell to add a note and a playground.
Nitrov3 currently seems to have issues with runtime config support in monorepos but it should work correctly in a new project.
I am not very familiar with bun so I couldn't get the imports from the node_modules to work and used a relative path instead.
For that reason also please check if I integrated it correctly into the build config.

Please see if you would like to have anything changed!

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@vercel
Copy link

vercel bot commented Jan 27, 2026

@schplitt is attempting to deploy a commit to the HRCD Projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link

github-actions bot commented Jan 27, 2026

Thank you for following the naming conventions! 🙏

@HugoRCD
Copy link
Owner

HugoRCD commented Jan 27, 2026

@schplitt I don't know if it's better, but I'd prefer to have an entry point that looks more like 'evlog/nitro/v3'. I don't really like having nitrov3 attached and it will be easier to migrate later by just removing /v3 and maybe replace v3 with v2 for migration 🤔. Otherwise, we'd also need a more 'complete' playground and tests as well! (If you don't have time, I can take care of it later)

@schplitt
Copy link
Author

@schplitt I don't know if it's better, but I'd prefer to have an entry point that looks more like 'evlog/nitro/v3'. I don't really like having nitrov3 attached and it will be easier to migrate later by just removing /v3 and maybe replace v3 with v2 for migration 🤔. Otherwise, we'd also need a more 'complete' playground and tests as well! (If you don't have time, I can take care of it later)

Should the 'complete' playground be like v2 or even more extensive?

@HugoRCD
Copy link
Owner

HugoRCD commented Jan 27, 2026

@schplitt I don't know if it's better, but I'd prefer to have an entry point that looks more like 'evlog/nitro/v3'. I don't really like having nitrov3 attached and it will be easier to migrate later by just removing /v3 and maybe replace v3 with v2 for migration 🤔. Otherwise, we'd also need a more 'complete' playground and tests as well! (If you don't have time, I can take care of it later)

Should the 'complete' playground be like v2 or even more extensive?

Ideally similar, but otherwise just a little less comprehensive is fine with me too. It's just so we can easily launch the app and quickly test that everything works without having to do too much setup.

@schplitt
Copy link
Author

Alright
I'll take care of that

@schplitt
Copy link
Author

Improved the playground to serve a basic UI to visualize the error aswell

Also moved nitrov3 to nitro/v3 in dist 🙂

@schplitt
Copy link
Author

schplitt commented Jan 27, 2026

I noticed that in v3 the error is transformed into an unhandled HTTPError before we have access to it
So this isn't actually working yet.

We would need to overwrite the entire error handler to be able to handle EvlogErrors correctly
Or have EvlogErrors extend HTTPErrors in nitro v3

@HugoRCD HugoRCD changed the title feat: add support for nitrov3 feat: add support for nitro v3 Jan 27, 2026
@HugoRCD
Copy link
Owner

HugoRCD commented Jan 27, 2026

I noticed that in v3 the error is transformed into an unhandled HTTPError before we have access to it So this isn't actually working yet.

We would need to overwrite the entire error handler to be able to handle EvlogErrors correctly Or have EvlogErrors extend HTTPErrors in nitro v3

I'll try to see how we can do that too

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 27, 2026

npm i https://pkg.pr.new/evlog@8

commit: cd2f9fb

@vercel
Copy link

vercel bot commented Jan 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
evlog-docs Ready Ready Preview, Comment Jan 31, 2026 1:35pm

@HugoRCD
Copy link
Owner

HugoRCD commented Jan 27, 2026

I just realized that I'm not even sure if this is supposed to work, or if it will ever work 😅

CleanShot 2026-01-27 at 22 09 21@2x

@schplitt
Copy link
Author

I just realized that I'm not even sure if this is supposed to work, or if it will ever work 😅

CleanShot 2026-01-27 at 22 09 21@2x

What exactly are you referring to?

@HugoRCD
Copy link
Owner

HugoRCD commented Jan 28, 2026

I just realized that I'm not even sure if this is supposed to work, or if it will ever work 😅
CleanShot 2026-01-27 at 22 09 21@2x

What exactly are you referring to?

I don't know if this syntax, where you put a plugin (imported from npm) directly into the plugin array, works. The documentation doesn't mention it

@schplitt
Copy link
Author

I am not sure what the future plans for nuxt and evlog are but as nitro will become framework agnostic and interop with vite plugins, maybe it would be a nice Idea to experiment with nitro modules:
nitrojs/nitro#3680

So that it could also be used with tanstack, etc.?
Though just an idea.

Let me know what your plans are going forward regarding nitro v3 and I'll see how I can help🙂

@HugoRCD
Copy link
Owner

HugoRCD commented Jan 28, 2026

@schplitt Oh, nice! So I think we should implement it like that, and clean up the repo to have a Nitro v2 playground and a Nitro v3 (update the PR with the latest features I added)

@schplitt
Copy link
Author

I noticed that in v3 the error is transformed into an unhandled HTTPError before we have access to it So this isn't actually working yet.
We would need to overwrite the entire error handler to be able to handle EvlogErrors correctly Or have EvlogErrors extend HTTPErrors in nitro v3

I'll try to see how we can do that too

What about your preferred solution for this?

@HugoRCD
Copy link
Owner

HugoRCD commented Jan 28, 2026

I noticed that in v3 the error is transformed into an unhandled HTTPError before we have access to it So this isn't actually working yet.
We would need to overwrite the entire error handler to be able to handle EvlogErrors correctly Or have EvlogErrors extend HTTPErrors in nitro v3

I'll try to see how we can do that too

What about your preferred solution for this?

So I would lean towards "simplicity" and extend HTTPError

@schplitt
Copy link
Author

schplitt commented Jan 28, 2026

I've looked into this a bit.
I think there is not really an "easy" way to do this.

First, we would make Evlog dependend on H3 v2 HTTPError which I think is incompatible with Nuxt and Nitro v2.

Second, the HTTPError interface is a bit different then what is currently expeced (e.g. extra body property for the returned response). It may be best to create another utility for Nitro v3 and export it from there to not have Nitro v2 and Nuxt be dependend on H3 v2.

@schplitt schplitt closed this Jan 28, 2026
@schplitt schplitt reopened this Jan 28, 2026
@schplitt
Copy link
Author

schplitt commented Jan 31, 2026

So I've finally had time to fix up the nitro/v3 functionality.

Now it uses H3's HTTPError. Though there are still a couple of issues that need to be resolved:

  1. Runtime Config Bundling Issue

When the plugin for Nitro v3 is bundled, it also bundles the reference to useRuntimeConfig() which results in it not actually having access to the correct runtime config but a mock. It also causes this warning in the terminal:

WARN  Nitro runtime imports detected without a builder or Nitro plugin. A stub implementation will be used.

TBH I have not yet found a better solution than actually copying the file into the package and having nitro transpile it at run/build time. But the necessary imports from evlog would need to be available from the package itself, though that seems to be possible. This would mean some logic cannot be shared (e.g., the shouldLog function).

Actually I think we can just mark nitro/runtime-config as external. This way the import is resolved by nitro at run/buildtime.

  1. Error Name Display

When the Error is logged, it still says HTTPError in the log message as we cannot overwrite the name of HTTPError:

16:42:33.410 ERROR [app] PUT /api/test/update 403 in 261ms
  ├─ requestId: b191342e-c394-4d2e-a5b3-b35df0574bb2
  ├─ user: id=999
  ├─ action: update_item
  ├─ item: name=My Item version=2.0
  ├─ validation: checked=true
  ├─ permissions: checked=true hasUpdate=false requiredRole=admin
  └─ error: name=HTTPError message=Update failed stack=HTTPError: Update failed
    at createError (file:///home/schplitt/vsc/evlog/packages/evlog/dist/nitro/v3/plugin.mjs:56:10)
    at file:///home/schplitt/vsc/evlog/apps/nitro-v3-playground/node_modules/.nitro/dev/index.mjs:819:9
Note: In Nitro v3, every Error besides HTTPError is automatically marked as unhandled which causes an even bigger error log
EvlogError: Update failed
    at createError (file:///home/schplitt/vsc/evlog/packages/evlog/dist/nitro/v3/plugin.mjs:59:10)
    at file:///home/schplitt/vsc/evlog/apps/nitro-v3-playground/node_modules/.nitro/dev/index.mjs:819:9 {
  cause: EvlogError: Update failed
      at createError (file:///home/schplitt/vsc/evlog/packages/evlog/dist/nitro/v3/plugin.mjs:59:10)
      at file:///home/schplitt/vsc/evlog/apps/nitro-v3-playground/node_modules/.nitro/dev/index.mjs:819:9 {
    cause: {
      cause: undefined,
      body: [Object],
      statusCode: 403,
      unhandled: false
    },
    status: 403,
    statusText: undefined,
    headers: undefined,
    data: undefined,
    body: {
      why: 'Insufficient permissions to update this resource',
      fix: 'Request admin privileges or contact your team lead',
      link: 'https://docs.example.com/permissions'
    },
    unhandled: false,
    why: 'Insufficient permissions to update this resource',
    fix: 'Request admin privileges or contact your team lead',
    link: 'https://docs.example.com/permissions'
  },
  status: 403,
  statusText: undefined,
  headers: undefined,
  data: undefined,
  body: {
    why: 'Insufficient permissions to update this resource',
    fix: 'Request admin privileges or contact your team lead',
    link: 'https://docs.example.com/permissions'
  },
  unhandled: true
}
16:39:56.331 ERROR [app] PUT /api/test/update 403 in 261ms
  ├─ requestId: 5bac1ec9-c6d6-47f2-9d56-da1b3a48e82c
  ├─ user: id=999
  ├─ action: update_item
  ├─ item: name=My Item version=2.0
  ├─ validation: checked=true
  ├─ permissions: checked=true hasUpdate=false requiredRole=admin
  └─ error: name=HTTPError message=Update failed stack=EvlogError: Update failed
    at createError (file:///home/schplitt/vsc/evlog/packages/evlog/dist/nitro/v3/plugin.mjs:59:10)
    at file:///home/schplitt/vsc/evlog/apps/nitro-v3-playground/node_modules/.nitro/dev/index.mjs:819:9

 ERROR  [request error] [unhandled] [PUT] http://localhost:3000/api/test/update

 
ℹ HTTPError: Update failed

 ⁃ at createError (/home/schplitt/vsc/evlog/packages/evlog/dist/nitro/v3/plugin.mjs:59:10)

   54 ┃      }
   55 ┃      return lines.join("\n");
   56 ┃    }
   57 ┃  }
   58 ┃  function createError(options) {
 ❯ 59 ┃    return new EvlogError(options);
   60 ┃  }
   61 ┃  const createEvlogError = createError;
   62 ┃  
   63 ┃  const plugin = definePlugin((nitroApp) => {
   64 ┃    const config = useRuntimeConfig();

 ⁃ (node_modules/.nitro/dev/index.mjs:819:9)

[CAUSE]
EvlogError {
  stack: 'Update failed\n' +
  'at createError (/home/schplitt/vsc/evlog/packages/evlog/dist/nitro/v3/plugin.mjs:59:10)\n' +
  'at ./node_modules/.nitro/dev/index.mjs:819:9)',
  message: 'Update failed',
  cause: {
    cause: undefined,
    body: [Object],
    statusCode: 403,
    unhandled: false,
  },
  status: 403,
  statusText: undefined,
  headers: undefined,
  data: undefined,
  body: {
    why: 'Insufficient permissions to update this resource',
    fix: 'Request admin privileges or contact your team lead',
    link: 'https://docs.example.com/permissions',
  },
  unhandled: false,
  why: 'Insufficient permissions to update this resource',
  fix: 'Request admin privileges or contact your team lead',
  link: 'https://docs.example.com/permissions',
}

It may be a bit confusing why the error from createError shows as HTTPError in the logs.

  1. Missing body

Currently Nitro v3 doesn't correctly pass the body back to the user (why, link, ...). But this is already being fixed.

Any wishes on how to best go forward with this @HugoRCD ?

@schplitt
Copy link
Author

schplitt commented Feb 8, 2026

@HugoRCD Just following up on this PR. I'm actively using Nitro v3 and would love to land this early support.

The issues from my last comment should all be easy to address:

  1. Solvable by marking runtime-config as external
  2. & 3. Can be handled via a custom error handler (same approach as Nitro v2)

I'm ready to bring this up to feature parity and merge it, but happy to wait for a more stable Nitro v3 release and keep the integration in my own project for now if you prefer.

Just let me know which direction works for you. I'd like to move forward when you have a moment.

@HugoRCD
Copy link
Owner

HugoRCD commented Feb 10, 2026

I don't know, I really want to have Nitro v3 support as soon as possible, but at the same time, I'm not sure if it's reasonable to wait for a more stable version? 🤔

@schplitt
Copy link
Author

Early support would be much appreciated.
As mainly existing features from Nitrov2 are used (plugins, error handler) I doubt there will be many breaking changes.

If you are worried about maintance, I am willing to help out as much as I can for keeping the v3 version up to date. 🙂

@HugoRCD
Copy link
Owner

HugoRCD commented Feb 10, 2026

Early support would be much appreciated.

As mainly existing features from Nitrov2 are used (plugins, error handler) I doubt there will be many breaking changes.

If you are worried about maintance, I am willing to help out as much as I can for keeping the v3 version up to date. 🙂

Nice, so let's go and make this happen !

@schplitt
Copy link
Author

schplitt commented Feb 10, 2026

@HugoRCD Brought it up to speed.
We can now just use the plain evlog createError function in nitro v3 aswell with the custom error handler.

Test with nitro v3 use a real development server.
To check if the actual runtime hooks are working is by logging them and catching the logs using consola.
For this to work correctly we run them sequentially and check the logs.
Was the easiest and cleanest solution I could think of right now, hope that's alright.
I also cleaned up the playground.

If anything like tests or features are missing, just tell me and I'll add them aswell.
You did so much here so could very well be I overlooked something ❤️

@HugoRCD
Copy link
Owner

HugoRCD commented Feb 10, 2026

@HugoRCD Brought it up to speed. We can now just use the plain evlog createError function in nitro v3 aswell with the custom error handler.

Test with nitro v3 use a real development server. To check if the actual runtime hooks are working is by logging them and catching the logs using consola. For this to work correctly we run them sequentially and check the logs. Was the easiest and cleanest solution I could think of right now, hope that's alright. I also cleaned up the playground.

If anything like tests or features are missing, just tell me and I'll add them aswell. You did so much here so could very well be I overlooked something ❤️

Ty 🙏 I'll take a look at that!

export default defineConfig({
serverDir: './',
// TODO: make playground work with evlog/nitro/v3
plugins: ['../../packages/evlog/src/nitro-v3/plugin.ts'],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weren't we supposed to run the system by just putting evlog/nitro/v3 here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the other issue, bun workspaces does not seem to resolve the dependency correctly and thus does not install it into the node_modules dir.
Does it work for you?

"~/*": ["./*"],
"evlog": ["../../packages/evlog/src/index.ts"],
"evlog/*": ["../../packages/evlog/src/*"]
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to customize tsconfig? Ideally, I would like the user to have as little to configure as possible

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bun workspaces does not resolve the types correctly.
It doesn't seem to correctly install the evlog package from the workspace on my machine

"@nuxt/kit": "^4.3.0",
"ufo": "^1.6.3"
},
"devDependencies": {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made sure that the lib is no longer a dependency. Do you think you can remove that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look how to minimize it/extract the logic to a local function.
Would inlining also be an option?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NitroV3 support

2 participants